home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / lwlib / lwlib-Xaw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-14  |  15.5 KB  |  577 lines

  1. /* The lwlib interface to Athena widgets.
  2.    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
  3.  
  4. This file is part of the Lucid Widget Library.
  5.  
  6. The Lucid Widget Library is free software; you can redistribute it and/or 
  7. modify it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. The Lucid Widget Library is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include <stdio.h>
  21.  
  22. #include "lwlib-Xaw.h"
  23.  
  24. #include <X11/StringDefs.h>
  25. #include <X11/IntrinsicP.h>
  26. #include <X11/CoreP.h>
  27. #include <X11/Shell.h>
  28.  
  29. #include <X11/Xaw/Scrollbar.h>
  30. #include <X11/Xaw/Dialog.h>
  31. #include <X11/Xaw/Form.h>
  32. #include <X11/Xaw/Command.h>
  33. #include <X11/Xaw/Label.h>
  34.  
  35. #include <X11/Xatom.h>
  36.  
  37. static void xaw_generic_callback (Widget, XtPointer, XtPointer);
  38.  
  39.  
  40. Boolean
  41. lw_xaw_widget_p (Widget widget)
  42. {
  43.   return (XtIsSubclass (widget, scrollbarWidgetClass) ||
  44.       XtIsSubclass (widget, dialogWidgetClass));
  45. }
  46.  
  47. static void
  48. xaw_update_scrollbar (widget_instance *instance, Widget widget,
  49.               widget_value *val)
  50. {
  51.   if (val->scrollbar_data)
  52.     {
  53.       scrollbar_values *data = val->scrollbar_data;
  54.       float widget_shown, widget_topOfThumb;
  55.       float new_shown, new_topOfThumb;
  56.  
  57.       /*
  58.        * First size and position the scrollbar widget.
  59.        */
  60.       XtVaSetValues (widget,
  61.              XtNx, data->scrollbar_x,
  62.              XtNy, data->scrollbar_y,
  63.              XtNwidth, data->scrollbar_width,
  64.              XtNheight, data->scrollbar_height,
  65.              0);
  66.  
  67.       /*
  68.        * Now the size the scrollbar's slider.
  69.        */
  70.  
  71.       XtVaGetValues (widget,
  72.              XtNtopOfThumb, &widget_topOfThumb,
  73.              XtNshown, &widget_shown,
  74.              0);
  75.  
  76.       new_shown = (double) data->slider_size /
  77.     (double) (data->maximum - data->minimum);
  78.  
  79.       new_topOfThumb = (double) (data->slider_position - data->minimum) /
  80.     (double) (data->maximum - data->minimum);
  81.  
  82.       if (new_shown > 1.0)
  83.     new_shown = 1.0;
  84.       if (new_shown < 0)
  85.     new_shown = 0;
  86.  
  87.       if (new_topOfThumb > 1.0)
  88.     new_topOfThumb = 1.0;
  89.       if (new_topOfThumb < 0)
  90.     new_topOfThumb = 0;
  91.  
  92.       if (new_shown != widget_shown || new_topOfThumb != widget_topOfThumb)
  93.     XawScrollbarSetThumb (widget, new_topOfThumb, new_shown);
  94.     }
  95. }
  96.  
  97. void
  98. xaw_update_one_widget (widget_instance *instance, Widget widget,
  99.                widget_value *val, Boolean deep_p)
  100. {
  101.   if (XtIsSubclass (widget, scrollbarWidgetClass))
  102.     {
  103.       xaw_update_scrollbar (instance, widget, val);
  104.     }
  105.   else if (XtIsSubclass (widget, dialogWidgetClass))
  106.     {
  107.       XtVaSetValues (widget, XtNlabel, val->contents->value, 0);
  108.     }
  109.   else if (XtIsSubclass (widget, commandWidgetClass))
  110.     {
  111.       Dimension bw = 0;
  112.       XtVaGetValues (widget, XtNborderWidth, &bw, 0);
  113.       if (bw == 0)
  114.     /* Don't let buttons end up with 0 borderwidth, that's ugly...
  115.        Yeah, all this should really be done through app-defaults files
  116.        or fallback resources, but that's a whole different can of worms
  117.        that I don't feel like opening right now.  Making Athena widgets
  118.        not look like shit is just entirely too much work.
  119.      */
  120.     XtVaSetValues (widget, XtNborderWidth, 1, 0);
  121.  
  122.       XtVaSetValues (widget,
  123.              XtNlabel, val->value,
  124.              XtNsensitive, val->enabled,
  125.              /* Force centered button text.  Se above. */
  126.              XtNjustify, XtJustifyCenter,
  127.              0);
  128.  
  129.       XtRemoveAllCallbacks (widget, XtNcallback);
  130.       XtAddCallback (widget, XtNcallback, xaw_generic_callback, instance);
  131.     }
  132. }
  133.  
  134. void
  135. xaw_update_one_value (widget_instance *instance, Widget widget,
  136.               widget_value *val)
  137. {
  138.   /* This function is not used by the scrollbars and those are the only
  139.      Athena widget implemented at the moment so do nothing. */
  140.   return;
  141. }
  142.  
  143. void
  144. xaw_destroy_instance (widget_instance *instance)
  145. {
  146.   if (XtIsSubclass (instance->widget, dialogWidgetClass))
  147.     /* Need to destroy the Shell too. */
  148.     XtDestroyWidget (XtParent (instance->widget));
  149.   else
  150.     XtDestroyWidget (instance->widget);
  151. }
  152.  
  153. void
  154. xaw_popup_menu (Widget widget, XEvent *event)
  155. {
  156.   /* An Athena menubar has not been implemented. */
  157.   return;
  158. }
  159.  
  160. void
  161. xaw_pop_instance (widget_instance *instance, Boolean up)
  162. {
  163.   Widget widget = instance->widget;
  164.  
  165.   if (up)
  166.     {
  167.       if (XtIsSubclass (widget, dialogWidgetClass))
  168.     {
  169.       /* For dialogs, we need to call XtPopup on the parent instead
  170.          of calling XtManageChild on the widget.
  171.          Also we need to hack the shell's WM_PROTOCOLS to get it to
  172.          understand what the close box is supposed to do!!
  173.        */
  174.       Display *dpy = XtDisplay (widget);
  175.       Widget shell = XtParent (widget);
  176.       Atom props [2];
  177.       int i = 0;
  178.       props [i++] = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
  179.       XChangeProperty (dpy, XtWindow (shell),
  180.                XInternAtom (dpy, "WM_PROTOCOLS", False),
  181.                XA_ATOM, 32, PropModeAppend,
  182.                (unsigned char *) props, i);
  183.  
  184.       /* Center the widget in its parent.  Why isn't this kind of crap
  185.          done automatically?  I thought toolkits were supposed to make
  186.          life easier?
  187.        */
  188.       {
  189.         unsigned int x, y, w, h;
  190.         Widget topmost = instance->parent;
  191.         w = shell->core.width;
  192.         h = shell->core.height;
  193.         while (topmost->core.parent && XtIsRealized (topmost->core.parent))
  194.           topmost = topmost->core.parent;
  195.         if (topmost->core.width < w) x = topmost->core.x;
  196.         else x = topmost->core.x + ((topmost->core.width - w) / 2);
  197.         if (topmost->core.height < h) y = topmost->core.y;
  198.         else y = topmost->core.y + ((topmost->core.height - h) / 2);
  199.         XtMoveWidget (shell, x, y);
  200.       }
  201.  
  202.       /* Finally, pop it up. */
  203.       XtPopup (shell, XtGrabNonexclusive);
  204.     }
  205.       else
  206.     XtManageChild (widget);
  207.     }
  208.   else
  209.     {
  210.       if (XtIsSubclass (widget, dialogWidgetClass))
  211.     XtUnmanageChild (XtParent (widget));
  212.       else
  213.     XtUnmanageChild (widget);
  214.     }
  215. }
  216.  
  217.  
  218. /* Dialog boxes */
  219.  
  220. static char overrideTrans[] =
  221.     "<Message>WM_PROTOCOLS: lwlib_delete_dialog()";
  222. static XtActionProc wm_delete_window (Widget shell, XtPointer closure,
  223.                       XtPointer call_data);
  224. static XtActionsRec xaw_actions [] = {
  225.   {"lwlib_delete_dialog", (XtActionProc) wm_delete_window}
  226. };
  227. static Boolean actions_initted = False;
  228.  
  229. static Widget
  230. make_dialog (char* name, Widget parent, Boolean pop_up_p,
  231.          char* shell_title, char* icon_name, Boolean text_input_slot,
  232.          Boolean radio_box, Boolean list,
  233.          int left_buttons, int right_buttons)
  234. {
  235.   Arg av [20];
  236.   int ac = 0;
  237.   int i, bc;
  238.   char button_name [255];
  239.   Widget shell;
  240.   Widget dialog;
  241.   Widget button;
  242.   XtTranslations override;
  243.  
  244.   if (! pop_up_p) abort (); /* not implemented */
  245.   if (text_input_slot) abort (); /* not implemented */
  246.   if (radio_box) abort (); /* not implemented */
  247.   if (list) abort (); /* not implemented */
  248.  
  249.   if (! actions_initted)
  250.     {
  251.       XtAppContext app = XtWidgetToApplicationContext (parent);
  252.       XtAppAddActions (app, xaw_actions,
  253.                sizeof (xaw_actions) / sizeof (xaw_actions[0]));
  254.       actions_initted = True;
  255.     }
  256.  
  257.   override = XtParseTranslationTable (overrideTrans);
  258.  
  259.   ac = 0;
  260.   XtSetArg (av[ac], XtNtitle, shell_title); ac++;
  261.   XtSetArg (av[ac], XtNallowShellResize, True); ac++;
  262.   XtSetArg (av[ac], XtNtransientFor, parent); ac++;
  263.   shell = XtCreatePopupShell ("dialog", transientShellWidgetClass,
  264.                   parent, av, ac);
  265.   XtOverrideTranslations (shell, override);
  266.  
  267.   ac = 0;
  268.   dialog = XtCreateManagedWidget (name, dialogWidgetClass, shell, av, ac);
  269.  
  270.   bc = 0;
  271.   button = 0;
  272.   for (i = 0; i < left_buttons; i++)
  273.     {
  274.       ac = 0;
  275.       XtSetArg (av [ac], XtNfromHoriz, button); ac++;
  276.       XtSetArg (av [ac], XtNleft, XtChainLeft); ac++;
  277.       XtSetArg (av [ac], XtNright, XtChainLeft); ac++;
  278.       XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
  279.       XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
  280.       XtSetArg (av [ac], XtNresizable, True); ac++;
  281.       sprintf (button_name, "button%d", ++bc);
  282.       button = XtCreateManagedWidget (button_name, commandWidgetClass,
  283.                       dialog, av, ac);
  284.     }
  285.   if (right_buttons)
  286.     {
  287.       /* Create a separator
  288.  
  289.      I want the separator to take up the slack between the buttons on
  290.      the right and the buttons on the left (that is I want the buttons
  291.      after the separator to be packed against the right edge of the
  292.      window) but I can't seem to make it do it.  
  293.        */
  294.       ac = 0;
  295.       XtSetArg (av [ac], XtNfromHoriz, button); ac++;
  296. /*  XtSetArg (av [ac], XtNfromVert, XtNameToWidget (dialog, "label")); ac++; */
  297.       XtSetArg (av [ac], XtNleft, XtChainLeft); ac++;
  298.       XtSetArg (av [ac], XtNright, XtChainRight); ac++;
  299.       XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
  300.       XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
  301.       XtSetArg (av [ac], XtNlabel, ""); ac++;
  302.       XtSetArg (av [ac], XtNwidth, 30); ac++;    /* #### aaack!! */
  303.       XtSetArg (av [ac], XtNborderWidth, 0); ac++;
  304.       XtSetArg (av [ac], XtNshapeStyle, XmuShapeRectangle); ac++;
  305.       XtSetArg (av [ac], XtNresizable, False); ac++;
  306.       XtSetArg (av [ac], XtNsensitive, False); ac++;
  307.       button = XtCreateManagedWidget ("separator",
  308.                       /* labelWidgetClass, */
  309.                       /* This has to be Command to fake out
  310.                      the Dialog widget... */
  311.                       commandWidgetClass,
  312.                       dialog, av, ac);
  313.     }
  314.   for (i = 0; i < right_buttons; i++)
  315.     {
  316.       ac = 0;
  317.       XtSetArg (av [ac], XtNfromHoriz, button); ac++;
  318.       XtSetArg (av [ac], XtNleft, XtChainRight); ac++;
  319.       XtSetArg (av [ac], XtNright, XtChainRight); ac++;
  320.       XtSetArg (av [ac], XtNtop, XtChainBottom); ac++;
  321.       XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++;
  322.       XtSetArg (av [ac], XtNresizable, True); ac++;
  323.       sprintf (button_name, "button%d", ++bc);
  324.       button = XtCreateManagedWidget (button_name, commandWidgetClass,
  325.                       dialog, av, ac);
  326.     }
  327.  
  328.   return dialog;
  329. }
  330.  
  331. Widget
  332. xaw_create_dialog (widget_instance* instance)
  333. {
  334.   char *name = instance->info->type;
  335.   Widget parent = instance->parent;
  336.   Widget widget;
  337.   Boolean pop_up_p = instance->pop_up_p;
  338.   char *shell_name = 0;
  339.   char *icon_name = 0;
  340.   Boolean text_input_slot = False;
  341.   Boolean radio_box = False;
  342.   Boolean list = False;
  343.   int total_buttons;
  344.   int left_buttons = 0;
  345.   int right_buttons = 1;
  346.  
  347.   switch (name [0]) {
  348.   case 'E': case 'e':
  349.     icon_name = "dbox-error";
  350.     shell_name = "Error";
  351.     break;
  352.  
  353.   case 'I': case 'i':
  354.     icon_name = "dbox-info";
  355.     shell_name = "Information";
  356.     break;
  357.  
  358.   case 'L': case 'l':
  359.     list = True;
  360.     icon_name = "dbox-question";
  361.     shell_name = "Prompt";
  362.     break;
  363.  
  364.   case 'P': case 'p':
  365.     text_input_slot = True;
  366.     icon_name = "dbox-question";
  367.     shell_name = "Prompt";
  368.     break;
  369.  
  370.   case 'Q': case 'q':
  371.     icon_name = "dbox-question";
  372.     shell_name = "Question";
  373.     break;
  374.   }
  375.   
  376.   total_buttons = name [1] - '0';
  377.  
  378.   if (name [3] == 'T' || name [3] == 't')
  379.     {
  380.       text_input_slot = False;
  381.       radio_box = True;
  382.     }
  383.   else if (name [3])
  384.     right_buttons = name [4] - '0';
  385.   
  386.   left_buttons = total_buttons - right_buttons;
  387.   
  388.   widget = make_dialog (name, parent, pop_up_p,
  389.             shell_name, icon_name, text_input_slot, radio_box,
  390.             list, left_buttons, right_buttons);
  391.  
  392.   return widget;
  393. }
  394.  
  395.  
  396. static void
  397. xaw_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
  398. {
  399.   widget_instance *instance = (widget_instance *) closure;
  400.   Widget instance_widget;
  401.   LWLIB_ID id;
  402.   XtPointer user_data;
  403.  
  404.   lw_internal_update_other_instances (widget, closure, call_data);
  405.  
  406.   if (! instance)
  407.     return;
  408.   if (widget->core.being_destroyed)
  409.     return;
  410.  
  411.   instance_widget = instance->widget;
  412.   if (!instance_widget)
  413.     return;
  414.  
  415.   id = instance->info->id;
  416.  
  417. #if 0
  418.   user_data = NULL;
  419.   XtVaGetValues (widget, XtNuserData, &user_data, 0);
  420. #else
  421.   /* Damn!  Athena doesn't give us a way to hang our own data on the
  422.      buttons, so we have to go find it...  I guess this assumes that
  423.      all instances of a button have the same call data. */
  424.   {
  425.     widget_value *val = instance->info->val->contents;
  426.     char *name = XtName (widget);
  427.     while (val)
  428.       {
  429.     if (val->name && !strcmp (val->name, name))
  430.       break;
  431.     val = val->next;
  432.       }
  433.     if (! val) abort ();
  434.     user_data = val->call_data;
  435.   }
  436. #endif
  437.  
  438.   if (instance->info->selection_cb)
  439.     instance->info->selection_cb (widget, id, user_data);
  440. }
  441.  
  442. static XtActionProc
  443. wm_delete_window (Widget shell, XtPointer closure, XtPointer call_data)
  444. {
  445.   LWLIB_ID id;
  446.   Widget *kids = 0;
  447.   Widget widget;
  448.   if (! XtIsSubclass (shell, shellWidgetClass))
  449.     abort ();
  450.   XtVaGetValues (shell, XtNchildren, &kids, 0);
  451.   if (!kids || !*kids)
  452.     abort ();
  453.   widget = kids [0];
  454.   if (! XtIsSubclass (widget, dialogWidgetClass))
  455.     abort ();
  456.   id = lw_get_widget_id (widget);
  457.   if (! id) abort ();
  458.  
  459.   {
  460.     widget_info *info = lw_get_widget_info (id);
  461.     if (! info) abort ();
  462.     if (info->selection_cb)
  463.       info->selection_cb (widget, id, (XtPointer) -1);
  464.   }
  465.  
  466.   lw_destroy_all_widgets (id);
  467.   return NULL;
  468. }
  469.  
  470.  
  471. /* Scrollbars */
  472.  
  473. #ifdef SCROLLBARS_ATHENA
  474. static void
  475. xaw_scrollbar_scroll (Widget widget, XtPointer closure, XtPointer call_data)
  476. {
  477.   widget_instance *instance = (widget_instance *) closure;
  478.   LWLIB_ID id;
  479.   scroll_event event_data;
  480.  
  481.   if (!instance || widget->core.being_destroyed)
  482.     return;
  483.  
  484.   id = instance->info->id;
  485.   event_data.slider_value = (int) call_data;
  486.   event_data.time = 0;
  487.  
  488.   if ((int) call_data > 0)
  489.     event_data.action = SCROLLBAR_PAGE_DOWN;
  490.   else
  491.     event_data.action = SCROLLBAR_PAGE_UP;
  492.  
  493.   if (instance->info->pre_activate_cb)
  494.     instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data);
  495. }
  496.  
  497. static void
  498. xaw_scrollbar_jump (Widget widget, XtPointer closure, XtPointer call_data)
  499. {
  500.   widget_instance *instance = (widget_instance *) closure;
  501.   LWLIB_ID id;
  502.   scroll_event event_data;
  503.   scrollbar_values *val =
  504.     (scrollbar_values *) instance->info->val->scrollbar_data;
  505.   float percent;
  506.  
  507.   if (!instance || widget->core.being_destroyed)
  508.     return;
  509.  
  510.   id = instance->info->id;
  511.  
  512.   percent = * (float *) call_data;
  513.   event_data.slider_value =
  514.     (int) (percent * (float) (val->maximum - val->minimum)) + val->minimum;
  515.  
  516.   event_data.time = 0;
  517.   event_data.action = SCROLLBAR_DRAG;
  518.  
  519.   if (instance->info->pre_activate_cb)
  520.     instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data);
  521. }
  522.  
  523. static Widget
  524. xaw_create_scrollbar (widget_instance *instance, int vertical)
  525. {
  526.   Arg av[20];
  527.   int ac = 0;
  528.   Widget scrollbar;
  529.  
  530.   XtSetArg (av [ac], XtNborderWidth, 0); ac++;
  531.   if (vertical)
  532.     {
  533.       XtSetArg (av [ac], XtNorientation, XtorientVertical); ac++;
  534.     }
  535.   else
  536.     {
  537.       XtSetArg (av [ac], XtNorientation, XtorientHorizontal); ac++;
  538.     }
  539.  
  540.   scrollbar =
  541.     XtCreateWidget (instance->info->name, scrollbarWidgetClass,
  542.             instance->parent, av, ac);
  543.  
  544.   XtRemoveAllCallbacks (scrollbar, "jumpProc");
  545.   XtRemoveAllCallbacks (scrollbar, "scrollProc");
  546.  
  547.   XtAddCallback (scrollbar, "jumpProc", xaw_scrollbar_jump,
  548.          (XtPointer) instance);
  549.   XtAddCallback (scrollbar, "scrollProc", xaw_scrollbar_scroll,
  550.          (XtPointer) instance);
  551.  
  552.   return scrollbar;
  553. }
  554.  
  555. static Widget
  556. xaw_create_vertical_scrollbar (widget_instance *instance)
  557. {
  558.   return xaw_create_scrollbar (instance, 1);
  559. }
  560.  
  561. static Widget
  562. xaw_create_horizontal_scrollbar (widget_instance *instance)
  563. {
  564.   return xaw_create_scrollbar (instance, 0);
  565. }
  566. #endif /* SCROLLBARS_ATHENA */
  567.  
  568. widget_creation_entry
  569. xaw_creation_table [] =
  570. {
  571. #ifdef SCROLLBARS_ATHENA
  572.   {"vertical-scrollbar",    xaw_create_vertical_scrollbar},
  573.   {"horizontal-scrollbar",    xaw_create_horizontal_scrollbar},
  574. #endif
  575.   {NULL, NULL}
  576. };
  577.